home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / dfue / elcheapofax / faxcmd / libfax / rcs / tty.c,v < prev    next >
Text File  |  1995-03-09  |  13KB  |  630 lines

  1. head    1.3;
  2. access;
  3. symbols
  4.     OCT93:1.3;
  5. locks;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.3
  10. date    93.07.13.05.41.27;    author Rhialto;    state Exp;
  11. branches;
  12. next    1.2;
  13.  
  14. 1.2
  15. date    93.06.11.16.15.25;    author Rhialto;    state Exp;
  16. branches;
  17. next    1.1;
  18.  
  19. 1.1
  20. date    93.06.11.15.19.27;    author Rhialto;    state Exp;
  21. branches;
  22. next    ;
  23.  
  24.  
  25. desc
  26. @Code for opening, reading, writing the serial port
  27. @
  28.  
  29.  
  30. 1.3
  31. log
  32. @Save on SDCMD_QUERY commands when not all available data is read.
  33. @
  34. text
  35. @/* $Id: tty.c,v 1.2 1993/06/11 16:15:25 Rhialto Exp $
  36.  * $Log: tty.c,v $
  37.  * Revision 1.2  1993/06/11  16:15:25  Rhialto
  38.  * First real RCS checkin
  39.  *
  40.  */
  41. /*
  42.   This file is part of El Cheapo Fax.
  43.  
  44.   (c) Copyright 1993 by Olaf 'Rhialto' Seibert.
  45.       All rights reserved.
  46.  
  47.     This program is free software; you can redistribute it and/or modify
  48.     it under the terms of the GNU General Public License as published by
  49.     the Free Software Foundation.
  50.  
  51.     This program is distributed in the hope that it will be useful,
  52.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  53.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  54.     GNU General Public License for more details.
  55.  
  56.     You should have received a copy of the GNU General Public License
  57.     along with this program; if not, write to the Free Software
  58.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  59. */
  60.  
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <stdarg.h>
  64. #include <string.h>
  65.  
  66. #define LIBRARIES_MATHFFP_H /* do not include! */
  67. #include <exec/types.h>
  68. #include <devices/serial.h>
  69. #include <devices/timer.h>
  70. #include <libraries/dos.h>
  71. #include <clib/exec_protos.h>
  72. #include <clib/alib_protos.h>
  73.  
  74. #include "c2proto.h"
  75. #include "log.h"
  76. #include "tty.h"
  77. #include "write.h"
  78. #include "read.h"
  79.  
  80. static int condition_tty(int fd);
  81.  
  82. struct IOExtSer *ior, *iow;
  83. struct MsgPort *Port;
  84. int fcstate;
  85.  
  86. /* termio fakes */
  87. /*
  88.  * These flow-control related functions are just stubs, because
  89.  * we do RTS/CTS flow control. The modem must be in &K3 mode
  90.  * and serial.device in SERF_7WIRE mode for this to work,
  91.  */
  92. int tty_fc(fd, state)
  93.      int fd;
  94.      fc_state state;
  95. {
  96.     log(L_DEBUG, "tty_fc state %d", state);
  97.     fcstate = state;
  98.  
  99.     return 0;
  100. }
  101.  
  102. int
  103. tcflow(int fd, int mode)
  104. {
  105.     log(L_DEBUG, "tcflow mode %s", mode==TCION ? "TCION" : "TCOOFF");
  106.     if (mode == TCION) {    /* trust caller on flow control mode */
  107.     static char c = XON;
  108.  
  109.     nwrite(fd, &c, 1);
  110.     }
  111.     /* if mode == TCOOFF stop output until XON received */
  112.     return 0;
  113. }
  114.  
  115. int
  116. ioctl(int fd, int command, int parameter)
  117. {
  118.     log(L_DEBUG, "ioctl command %d parm %d (ignored)", command, parameter);
  119. }
  120.  
  121. static int condition_tty(fd)
  122.      int fd;
  123. {
  124.     WaitIO((struct IORequest *)iow);
  125.     iow->IOSer.io_Command = SDCMD_SETPARAMS;
  126.     iow->io_RBufLen = 8192;
  127.     iow->io_ExtFlags = 0;
  128.     iow->io_Baud = 19200;
  129.     iow->io_ReadLen = 8;
  130.     iow->io_WriteLen = 8;
  131.     iow->io_StopBits = 1;
  132.     iow->io_SerFlags &= ~(SERF_EOFMODE | SERF_PARTY_ON | SERF_PARTY_ODD);
  133.     iow->io_SerFlags |= SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  134.  
  135.     DoIO((struct IORequest *)iow);
  136.     iow->IOSer.io_Flags = IOF_QUICK;
  137.     if (iow->IOSer.io_Error) {
  138.     log(L_EMERG, "condition_tty: can't set attrs: %d", iow->IOSer.io_Error);
  139.     return -1;
  140.     }
  141. }
  142.  
  143. int tty_open(filename)
  144.      char *filename;
  145. {
  146.     int unit;
  147.     char *devicename;
  148.  
  149.     log(L_DEBUG, "tty_open(%s)", filename);
  150.     /* 0/serial.device */
  151.     if (devicename = strchr(filename, '/')) {
  152.     devicename++;
  153.     unit = atoi(filename);
  154.     } else if ('0' <= filename[0] && filename[0] <= '9') {
  155.     devicename = "serial.device";
  156.     unit = atoi(filename);
  157.     } else {
  158.     devicename = filename;
  159.     unit = 0;
  160.     }
  161.  
  162.     Port = CreatePort(NULL, 0);
  163.     if (Port == NULL) {
  164.     log(L_EMERG, "no MsgPort");
  165.     return -1;
  166.     }
  167.     iow = (struct IOExtSer *)CreateExtIO(Port, sizeof (*iow));
  168.     iow->IOSer.io_Flags = IOF_QUICK;
  169.     ior = (struct IOExtSer *)CreateExtIO(Port, sizeof (*ior));
  170.     if (ior == NULL || iow == NULL) {
  171.     log(L_EMERG, "no I/O requests");
  172.     tty_close(1);
  173.     return -1;
  174.     }
  175.  
  176.     /* Should be O_NDELAY !! */
  177.     /* Should only be shared when we're being called from a front-door */
  178.     if (OpenDevice(devicename, unit, (struct IORequest *)iow, 0L)) {
  179.     iow->io_SerFlags = SERF_SHARED;
  180.     if (OpenDevice(devicename, unit, (struct IORequest *)iow, 0L)) {
  181.         log(L_EMERG, "can't open fax modem device: %d", iow->IOSer.io_Error);
  182.         tty_close(1);
  183.         return -1;
  184.     }
  185.     log(L_NOTICE, "opened serial port in shared mode");
  186.     }
  187.  
  188.     if (condition_tty(1) < 0) {
  189.     tty_close(1);
  190.     return -1;
  191.     }
  192.     *ior = *iow;
  193.  
  194.     return 1;        /* fd will be ignored by us */
  195. }
  196.  
  197. int tty_close(fd)
  198.      int fd;
  199. {
  200.     if (iow) {
  201.     if (iow->IOSer.io_Device != 0 && (long) iow->IOSer.io_Device != -1)
  202.         CloseDevice((struct IORequest *)iow);
  203.     iow->IOSer.io_Device = 0;
  204.     DeleteExtIO((struct IORequest *)iow);
  205.     iow = NULL;
  206.     }
  207.     if (ior) {
  208.     DeleteExtIO((struct IORequest *)ior);
  209.     ior = NULL;
  210.     }
  211.     if (Port) {
  212.     DeletePort(Port);
  213.     Port = NULL;
  214.     }
  215.     return 0;
  216. }
  217.  
  218. /* write.c */
  219.  
  220. unsigned char wbuf[256];
  221.  
  222. int nwrite(fd, buf, bufsize)
  223.      int fd;
  224.      char *buf;
  225.      int bufsize;
  226. {
  227.     int done = bufsize;
  228.  
  229.     if (WaitIO((struct IORequest *)iow)) {
  230.     iow->IOSer.io_Flags = IOF_QUICK;
  231.     log(L_EMERG, "do_write: previous write failed: %d", iow->IOSer.io_Error);
  232.     return -1;
  233.     }
  234.     iow->IOSer.io_Command = CMD_WRITE;
  235.     while (bufsize > sizeof(wbuf)) {
  236.     iow->IOSer.io_Data = buf;
  237.     iow->IOSer.io_Length = sizeof(wbuf);
  238.     DoIO((struct IORequest *)iow);
  239.     buf += sizeof(wbuf);
  240.     bufsize -= sizeof(wbuf);
  241.     }
  242.     memcpy(wbuf, buf, bufsize);
  243.     iow->IOSer.io_Data = wbuf;
  244.     iow->IOSer.io_Length = bufsize;
  245.     SendIO((struct IORequest *)iow);
  246.  
  247.     return done;
  248. }
  249.  
  250. int fdprintf(int fd, char *format, ...)
  251. {
  252.     va_list ap;
  253.     char buf[1024];
  254.  
  255.     va_start(ap, format);
  256.     vsprintf(buf, format, ap);
  257.     va_end(ap);
  258.  
  259.     log(L_DEBUG, "fdprintf: %s", buf);
  260.     return (nwrite(fd, buf, strlen(buf)));
  261. }
  262.  
  263. /* termio fakes */
  264. int
  265. tcflush(int fd, int ioctl)
  266. {
  267.     log(L_DEBUG, "tcflush ioctl %d", ioctl);
  268.     if (ioctl & TCIFLUSH) {
  269.     ior->IOSer.io_Command = CMD_CLEAR;
  270.     DoIO((struct IORequest *)ior);
  271.     }
  272.     return 0;
  273. }
  274.  
  275. int
  276. tcdrain(int fd)
  277. {
  278.     log(L_DEBUG, "tcdrain");
  279.     WaitIO((struct IORequest *)iow);
  280.     iow->IOSer.io_Flags = IOF_QUICK;
  281.     if (iow->IOSer.io_Error) {
  282.     log(L_EMERG, "tcdrain: previous write failed: %d", iow->IOSer.io_Error);
  283.     return -1;
  284.     }
  285.     return 0;
  286. }
  287.  
  288. /* read.c */
  289.  
  290. static int timeout_init(void);
  291. static void timeout_set(int seconds);
  292. static int read_internal(int fd, char * buf, int bufsize);
  293.  
  294. struct timerequest *TimeOut;
  295. int tmoinit;
  296.  
  297. static int timeout_init()
  298. {
  299.     TimeOut = (struct timerequest *)CreateExtIO(Port, sizeof(*TimeOut));
  300.     if (TimeOut == NULL) {
  301.     log(L_EMERG, "no timerequest");
  302.     return -1;
  303.     }
  304.     if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)TimeOut, 0)) {
  305.     DeleteExtIO((struct IORequest *)TimeOut);
  306.     TimeOut = NULL;
  307.     log(L_EMERG, "no timer device");
  308.     return -1;
  309.     }
  310.  
  311.     tmoinit = 1;
  312.  
  313.     return 0;
  314. }
  315.  
  316. static void timeout_set(seconds)
  317.      int seconds;
  318. {
  319.     if (seconds) {
  320.     TimeOut->tr_node.io_Command = TR_ADDREQUEST;
  321.     TimeOut->tr_time.tv_secs = seconds;
  322.     TimeOut->tr_time.tv_micro = 0;
  323.     SendIO((struct IORequest *)TimeOut);
  324.     } else {
  325.     if (CheckIO((struct IORequest *)TimeOut) == 0) {
  326.         AbortIO((struct IORequest *)TimeOut);
  327.     }
  328.     WaitIO((struct IORequest *)TimeOut);
  329.     }
  330. }
  331.  
  332. /*
  333.  * Like a normal read, except poll for input.  Return -1 on error or
  334.  * 0 if no data is available.
  335.  */
  336. int pread(fd, buf, bufsize)
  337.      int fd;
  338.      char *buf;
  339.      int bufsize;
  340. {
  341.     static int avail;
  342.  
  343.     if (avail <= 0) {
  344.     ior->IOSer.io_Command = SDCMD_QUERY;
  345.     DoIO((struct IORequest *)ior);
  346.     avail = ior->IOSer.io_Actual;
  347.     }
  348.  
  349.     if (avail > 0) {
  350.     if (avail < bufsize)
  351.         bufsize = avail;
  352.     avail -= bufsize;
  353.  
  354.     ior->IOSer.io_Command = CMD_READ;
  355.     ior->IOSer.io_Data = buf;
  356.     ior->IOSer.io_Length = bufsize;
  357.     if (DoIO((struct IORequest *)ior) != 0) {
  358.         log(L_ERR, "pread read error");
  359.         return -1;
  360.     }
  361.     return (int)ior->IOSer.io_Actual;
  362.     }
  363.     return 0;
  364. }
  365.  
  366. /* Original "documentation":
  367.  * Read from fd into a buf with maxlength bufsize.  Return when
  368.  * a minimum of minsize bytes have been read.  Wait a maximum
  369.  * of seconds seconds before timing out.  Return 0 if a timeout
  370.  * occured.  Return -1 if the read failed.  In other cases,
  371.  * return the total bytes read.
  372.  */
  373. /* What the actual implementation did:
  374.  * Wait for the timeout, or data being available.
  375.  * If timeout, return 0.
  376.  * If data available, grab all of it (up to bufsize) and return amount.
  377.  */
  378. static int read_internal(fd, buf, bufsize)
  379.      int fd;
  380.      char *buf;
  381.      int bufsize;
  382. {
  383.     int bytes;
  384.     long sigmask;
  385.  
  386.     bytes = pread(fd, buf, bufsize);
  387.     if (bytes)
  388.     return bytes;
  389.  
  390.     /* No data. Wait for something to happen. */
  391.     ior->IOSer.io_Command = CMD_READ;
  392.     ior->IOSer.io_Data = buf;
  393.     ior->IOSer.io_Length = 1;
  394.     SendIO((struct IORequest *)ior);
  395.  
  396.     /* Wait for data or timeout. */
  397. wait:
  398.     sigmask = Wait(1L << Port->mp_SigBit | SIGBREAKF_CTRL_C);
  399.     sigmask &= SIGBREAKF_CTRL_C;
  400.  
  401.     /* Was it data? */
  402.     if (CheckIO((struct IORequest *)ior)) {
  403.     WaitIO((struct IORequest *)ior);
  404.     bytes = ior->IOSer.io_Actual;
  405.     if (bytes && bufsize > 1) {
  406.         bytes += pread(fd, buf + 1, bufsize - 1);
  407.     }
  408.     log(L_DEBUG, "got %d: \"%.*s\"", bytes, bytes, buf);
  409.     return bytes;
  410.     }
  411.     /* Not a false alarm? */
  412.     if (sigmask == 0 &&
  413.     CheckIO((struct IORequest *)TimeOut) == 0)
  414.     goto wait;
  415.  
  416.     /* Nope - a timeout */
  417.     AbortIO((struct IORequest *)ior);
  418.     WaitIO((struct IORequest *)ior);
  419.  
  420.     log(L_ERR, "read abort or timeout");
  421.  
  422.     /* Maybe the abort didn't work */
  423.     return ior->IOSer.io_Actual > 0 ? ior->IOSer.io_Actual :
  424.        sigmask ? -1 : 0;
  425. }
  426.  
  427. /*
  428.  * Like a normal read, except use a timeout.  Returns the bytes
  429.  * that were read.
  430.  *
  431.  * Return codes:
  432.  *     0    timeout
  433.  *    -1    failure, see errno for more information
  434.  */
  435. int tread(fd, buf, bufsize, timeout)
  436.      int fd;
  437.      char *buf;
  438.      int bufsize;
  439.      int timeout;
  440. {
  441.     int bytes;
  442.  
  443.     if (!tmoinit)
  444.       timeout_init();
  445.  
  446.     timeout_set(timeout);
  447.     bytes = read_internal(fd, buf, bufsize);
  448.     timeout_set(0);
  449.  
  450.     return (bytes);
  451. }
  452.  
  453. /*
  454.   Read a string, terminated by a CR, into the buffer.  Return the
  455.   length of characters read, include the CR.  Skips any NL chars
  456.   that might be encountered, since they can safely be ignored.
  457.  
  458.   Return codes:
  459.       0    timeout
  460.      -1    failure, see errno for more information
  461. */
  462. int fdgets(fd, buf, bufsize)
  463.      int fd;
  464.      char *buf;
  465.      int bufsize;
  466. {
  467.     char *bufp = buf;
  468.     int i;
  469.  
  470.     for (i = 0; i < bufsize; i++) {
  471.     char c;
  472.  
  473.     switch (read_internal(fd, &c, 1)) {
  474.       case 0:
  475.         return (0);
  476.       case 1:
  477.         if (c != '\n') {
  478.         *bufp++ = c;
  479.         if (c == '\r')
  480.           return (i+1);
  481.         }
  482.         break;
  483.       default:
  484.         return (-1);
  485.     }
  486.     }
  487.  
  488.     return (i);
  489. }
  490.  
  491. /*
  492.  * Read a line, until a NL, with default timeout.  Return -1 on
  493.  * failure.  Return 0 on timeout.  Otherwise, return total bytes
  494.  * read;
  495.  */
  496. int tfdgets(fd, buf, bufsize, timeout)
  497.      int fd;
  498.      char *buf;
  499.      int bufsize;
  500.      int timeout;
  501. {
  502.     int bytes;
  503.  
  504.     if (!tmoinit)
  505.       timeout_init();
  506.  
  507.     timeout_set(timeout);
  508.     bytes = fdgets(fd, buf, bufsize);
  509.     timeout_set(0);
  510.  
  511.     return (bytes);
  512. }
  513.  
  514. int wait_for_char(fd, c_expect, timeout)
  515.      int fd;
  516.      char c_expect;
  517.      int timeout;
  518. {
  519.     if (!tmoinit)
  520.       timeout_init();
  521.  
  522.     timeout_set(timeout);
  523.  
  524.     log(L_DEBUG, "waiting %d seconds for char %d", timeout, c_expect);
  525.  
  526.     for (;;) {
  527.     char c;
  528.  
  529.     if (read_internal(fd, &c, 1) != 1) {
  530.         timeout_set(0);
  531.         return (-1);
  532.     }
  533.  
  534.     if (c == c_expect)
  535.       return (0);
  536.     }
  537. }
  538.  
  539. int wait_for_string(fd, s_expect, timeout)
  540.      int fd;
  541.      char *s_expect;
  542.      int timeout;
  543. {
  544.     if (!tmoinit)
  545.       timeout_init();
  546.  
  547.     timeout_set(timeout);
  548.  
  549.     log(L_DEBUG, "waiting %d seconds for string %s", timeout, s_expect);
  550.  
  551.     for (;;) {
  552.     char buf[BUFSIZ];
  553.     int bytes;
  554.  
  555.     if ((bytes = fdgets(fd, buf, sizeof(buf))) <= 0) {
  556.         timeout_set(0);
  557.         return (-1);
  558.     }
  559.  
  560.     if (bytes > 1) {
  561.         buf[bytes] = '\0';
  562.  
  563.         if (strncmp(s_expect, buf, strlen(s_expect)) == 0)
  564.           return (0);
  565.     }
  566.     }
  567. }
  568. @
  569.  
  570.  
  571. 1.2
  572. log
  573. @First real RCS checkin
  574. @
  575. text
  576. @d1 5
  577. a5 2
  578. /* $Id$
  579.  * $Log$
  580. d307 1
  581. a307 2
  582.     ior->IOSer.io_Command = SDCMD_QUERY;
  583.     DoIO((struct IORequest *)ior);
  584. d309 5
  585. a313 3
  586.     if (ior->IOSer.io_Actual > 0) {
  587.     if (ior->IOSer.io_Actual < bufsize)
  588.         bufsize = ior->IOSer.io_Actual;
  589. d315 5
  590. d327 1
  591. d329 1
  592. a329 1
  593.     return (int)ior->IOSer.io_Actual;
  594. @
  595.  
  596.  
  597. 1.1
  598. log
  599. @Initial revision
  600. @
  601. text
  602. @d1 3
  603. d68 1
  604. a68 1
  605.     log(L_DEBUG, "tcflow mode %d", mode);
  606. d81 1
  607. a81 1
  608.     log(L_DEBUG, "ioctl command %d parm %d", command, parameter);
  609. d95 2
  610. a96 1
  611.     iow->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  612. d140 1
  613. d142 7
  614. a148 3
  615.     log(L_EMERG, "can't open fax modem device: %d", iow->IOSer.io_Error);
  616.     tty_close(1);
  617.     return -1;
  618. d157 1
  619. a157 1
  620.     return 1;        /* fd will be ignored */
  621. a317 1
  622.     return (int)ior->IOSer.io_Actual;
  623. d319 1
  624. a319 1
  625.     return 0;
  626. d376 1
  627. a376 1
  628.     log(L_ERR, "read timeout");
  629. @
  630.